package erwiki.ui.app.parts;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.elwiki_data.WikiPage;
//import org.elwiki.api.IApplicationSession;
//import org.elwiki.api.search.ISearchManager;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;

import erwiki.Wiki;
import erwiki.api.core.Engine;
import erwiki.api.core.WikiContext;
import erwiki.api.exceptions.ProviderException;
import erwiki.api.search.SearchManager;
import erwiki.api.search.SearchResult;
import erwiki.ui.app.internal.ImageResource;
import erwiki.ui.app.internal.ImageUtility;
import jakarta.annotation.PostConstruct;
import jakarta.inject.Inject;

public class SearchView {

	class PagesTableLabelProvider extends LabelProvider implements ITableLabelProvider {
		private static final long serialVersionUID = -5564357223265889570L;

		@Override
		public Image getColumnImage(Object element, int columnIndex) {
			Image result = null;
			if (element instanceof SearchResult) {
				SearchResult searchResult = (SearchResult) element;
				int relevance = searchResult.getScore();
				if (columnIndex == 1) {
					result = ImageResource.getImage(ImageResource.IMG_DOOR_OUT);
					//result = resize(result, SearchViewPart.this.imageRatio * relevance);
					result = ImageUtility.makeImage(relevance);
				}
			}
			return result;
		}

		@Override
		public String getColumnText(Object element, int columnIndex) {
			String result = "";

			if (element instanceof SearchResult) {
				SearchResult searchResult = (SearchResult) element;
				switch (columnIndex) {
				case 0: {
					WikiPage wikiPage = searchResult.getPage();
					result = wikiPage.getName();
				}
					break;

				case 1: {
					int relevance = searchResult.getScore();
					result = String.valueOf(relevance);
				}
					break;

				default:
					result = "--";
					break;
				}

			}

			return result;
		}
	}

	private static final Logger log = Logger.getLogger(SearchView.class);

	public static final String ID = "erwiki.ui.part.search"; //$NON-NLS-1$

	public static final String PROP_SEARCH_REQUEST = "searchRequest";

	private Table table;

	private TableViewer tableViewer;

	private int baseRelevance = 0;

	ISelection selection = StructuredSelection.EMPTY;

	ListenerList<ISelectionChangedListener> selectionChangedListeners = new ListenerList<>();

	@Inject
	private Engine engine;

	// == CODE ================================================================

	@Inject
	public SearchView() {
		//:FVK: -- E3 old code
		//this.applicationSession = AppUiActivator.getDefault().getAppSession();

		//Deprecated
		//BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
		//ServiceReference<?> serviceReference = bundleContext.getServiceReference(Engine.class.getName());
		//engine = (Engine) bundleContext.getService(serviceReference);
	}
	
	/**
	 * Create contents of the view part.
	 * 
	 * @param parent
	 */
	@PostConstruct
	public void postConstruct(Composite parent) {
		Composite container = new Composite(parent, SWT.NONE);
		container.setLayout(new GridLayout(1, false));
		{
			this.tableViewer = new TableViewer(container, SWT.BORDER | SWT.FULL_SELECTION);
			this.tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
				public void selectionChanged(SelectionChangedEvent event) {
					IStructuredSelection ss = (IStructuredSelection) event.getSelection();
					if (!ss.isEmpty()) {
						pageSelected(ss);
					}
				}
			});
			this.table = this.tableViewer.getTable();
			this.tableViewer.getTable().setHeaderVisible(true);
			this.table.setLinesVisible(true);
			this.table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
			createTableColumns(this.tableViewer);
		}

		// --------------------------------------------------------------------

		this.tableViewer.getControl().addFocusListener(new FocusListener() {
			private static final long serialVersionUID = -8526431638097754942L;

			@Override
			public void focusLost(FocusEvent arg0) {
				//:FVK: -- E3 old code
				//SearchViewPart.this.selection = StructuredSelection.EMPTY;
			}

			@Override
			public void focusGained(FocusEvent arg0) {
				//
			}
		});

		/*:FVK: -- E3 old code
		createActions();
		initializeToolBar();
		initializeMenu();*/

		/*:FVK: -- E3 old code
		this.addPartPropertyListener(new IPropertyChangeListener() {
			private static final long serialVersionUID = -7071414183319791959L;

			@Override
			public void propertyChange(PropertyChangeEvent event) {
				String property = event.getProperty();
				if (PROP_SEARCH_REQUEST.equals(property)) {
					Object value = event.getNewValue();
					if (value instanceof String) {
						searchPages((String) value);
					} else {
						LOG.error("Internal error: failed argument casting.");
					}
				}
			}
		});

		getSite().setSelectionProvider(this);*/
	}
	
	private void createTableColumns(TableViewer tableViewer2) {
		{
			TableViewerColumn tblvcPage = new TableViewerColumn(this.tableViewer, SWT.NONE);
			TableColumn tblclmnPage = tblvcPage.getColumn();
			tblclmnPage.setWidth(400);
			tblclmnPage.setText("Page");
			tblvcPage.setLabelProvider(new CellLabelProvider() {
				private static final long serialVersionUID = 3793985215078169887L;

				@Override
				public void update(ViewerCell cell) {
					Object element = cell.getElement();
					if (element instanceof SearchResult) {
						SearchResult searchResult = (SearchResult) element;
/*:FVK: -- E3 old code
						WikiPage wikiPage = searchResult.getPage();
						cell.setText(wikiPage.getName());
*/
					}
				}
			});
		}
		{
			TableViewerColumn tblvcRelevance = new TableViewerColumn(this.tableViewer, SWT.NONE);
			TableColumn tblclmnRelevance = tblvcRelevance.getColumn();
			tblclmnRelevance.setAlignment(SWT.LEFT);
			tblclmnRelevance.setWidth(800);
			tblclmnRelevance.setText("Relevance");
			tblvcRelevance.setLabelProvider(new CellLabelProvider() {
				private static final long serialVersionUID = -1899416655104294098L;

				@Override
				public void update(ViewerCell cell) {
					Object element = cell.getElement();
					if (element instanceof SearchResult) {
						SearchResult searchResult = (SearchResult) element;
						float relevance = searchResult.getScore();
						float d = relevance / SearchView.this.baseRelevance;
						float l = (float) (20 * Math.log10(d));
						int ld = Math.round(l);
						// String.valueOf(relevance)
						String str = String.format("%4.0f    %d    %f    %d", //
								relevance, SearchView.this.baseRelevance, d, ld); // l

						cell.setText(str);
						cell.setBackground(getColor((int) (255 + ld * 1.5), 255 + ld, (int) (255 + ld * 1.25)));
					}
				}
			});
		}
		this.tableViewer.setContentProvider(new ArrayContentProvider());
		//this.tableViewer.setLabelProvider(new PagesTableLabelProvider());

	}

	Color getColor(int systemColorId) {
		Display d = Display.getCurrent();
		return d.getSystemColor(systemColorId);
	}

	Color getColor(int r, int g, int b) {
		Color color = getColor(new RGB(100, 100, 100));
		try {
			color = getColor(new RGB(r, g, b));
		} catch (IllegalArgumentException e) {
			System.out.printf("Error for RGB: %d %d %d\n", r, g, b);
		}
		return color;
	}

	private static Map<RGB, Color> m_colorMap = new HashMap<>();

	private Color getColor(RGB rgb) {
		Color color = m_colorMap.get(rgb);
		if (color == null) {
			Display display = Display.getCurrent();
			color = new Color(display, rgb);
			m_colorMap.put(rgb, color);
		}
		return color;
	}

	/**
	 * Transform type of selection: SearchResult -> WikiPage.
	 * 
	 * @param selection
	 */
	protected void pageSelected(IStructuredSelection selection) {
		SearchResult searchResult = (SearchResult) selection.getFirstElement();
		//:FVK: -- E3 old code
		//setSelection(new StructuredSelection(searchResult.getPage()));
	}

	public void searchPages(String query) {
		SearchManager searchManager = this.engine.getManager(SearchManager.class);

		try {
			//:FVK: --было?-- WikiContext context = Wiki.context().create(engine, null); // workaround. :FVK: контекст создан для E4.
			Collection<SearchResult> searchResult = searchManager.findPages(query);
			this.baseRelevance = 0;
			searchResult.forEach((res) -> {
				int relevance = res.getScore();
				if (this.baseRelevance < relevance)
					this.baseRelevance = relevance;
			});
			this.tableViewer.setInput(searchResult);
			this.tableViewer.refresh(true);
			//			for (SearchResult r : searchResult) {
			//				WikiPage page = r.getPage();
			//				int score = r.getScore();
			//				System.out.printf("%60s - %d\n", page.getName(), score);
			//			}
		} catch (ProviderException | IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
